/**********************************************
*  Classes:   TransformNode
*  Desc:      Defines a transform node
*			  in the Scene Graph. Derives from 
*			  SceneNode
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#ifndef TRANSFORMNODE_H
#define TRANSFORMNODE_H

#include "Transform.h"
#include "Quaternion.h"
#include "SceneNode.h"
#include "NodeProperty.h"
#include "Light.h"
#include "BoundingBox.h"
#include <map>

class TransformNode : public SceneNode
{
public:

	typedef std::list<LightPtr> LightList;

	TransformNode();
	virtual ~TransformNode();

	// adds a property to the map
	void AddProperty (NodePropertyPtr p);
	// get a property
	NodePropertyPtr GetProperty 
		(NodeProperty::PropertyType type);
	// remove a property
	void RemoveProperty(NodeProperty::PropertyType type);
	// add a light to the list
	void AddLight(LightPtr light)
	{
		if (!light) return;

		if (m_lLights.size() >= 8) return;

		m_lLights.push_back(light);

		m_bUpdateLights = true;
	}
	// remove a light. when a light 
	// is removed it is not automatically
	// removed from its children
	void RemoveLight(LightPtr light)
	{
		if (!light) return;
		m_lLights.remove(light);
	}

	// sort lights according to distance
	// from a certain position
	void SortLights();

	// getters - setters
	
	virtual const NodeType GetType() const
	{
		return NODE_TRANSFORM;
	}

	const mth::Transform GetTransform() const
	{
		return mth::Transform (m_qLocalRotation.ToMatrix(),
			m_vLocalPos);
	}

	const mth::Transform GetGlobalTransform() const
	{
		return mth::Transform (m_qGlobalRotation.ToMatrix(),
			m_vGlobalPos);
	}

	const mth::Vector3& GetTranslation() const
	{
		return m_vLocalPos;
	}

	const mth::Vector3& GetGlobalTranslation() const
	{
		return m_vGlobalPos;
	}

	const mth::Matrix33 GetRotation() const
	{
		return m_qLocalRotation.ToMatrix();
	}

	const mth::Matrix33 GetGlobalRotation() const
	{
		return m_qGlobalRotation.ToMatrix();
	}

	const mth::Quaternion& GetRotationQuat() const
	{
		return m_qLocalRotation;
	}

	const mth::Quaternion& GetGlobalRotationQuat() const
	{
		return m_qGlobalRotation;
	}

	const mth::Vector3& GetScale() const
	{
		return m_vScale;
	}

	const LightList& GetLightList() const
	{
		return m_lLights;
	}

	bool HasLights() const
	{
		return m_lLights.size() > 0;
	}

	const BoundingBox& GetBoundingBox() const
	{
		return m_BoundingBox;
	}

	void SetTransform(const mth::Transform& t)
	{
		m_vLocalPos = t.GetTranslation();
		m_qLocalRotation.FromMatrix(t.GetRotation());
	}

	void SetGlobalTransform(const mth::Transform& t)
	{
		m_vGlobalPos = t.GetTranslation();
		m_qGlobalRotation.FromMatrix(t.GetRotation());
	}

	void SetTranslation(const mth::Vector3& t)
	{
		m_vLocalPos = t;
	}

	void SetGlobalTranslation(const mth::Vector3& t)
	{
		m_vGlobalPos = t;
	}

	void SetRotation(const mth::Matrix33& r)
	{
		m_qLocalRotation.FromMatrix(r);
	}

	void SetGlobalRotation(const mth::Matrix33& r)
	{
		m_qGlobalRotation.FromMatrix(r);
	}

	void SetRotation(const mth::Quaternion& q)
	{
		m_qLocalRotation = q;
	}

	void SetGlobalRotation(const mth::Quaternion& q)
	{
		m_qGlobalRotation = q;
	}

	void SetScale(const mth::Vector3& s)
	{
		m_vScale = s;
	}

	void SetBoundingBox (const BoundingBox& box)
	{
		m_BoundingBox = box;
	}

	void SetInitialBoundingBox (const BoundingBox& box)
	{
		m_InitialBoundingBox = box;
		m_BoundingBox = box;
		m_BoundingBox.Scale(m_vScale);

	}
	
	void ResetBoundingBox()
	{
		m_BoundingBox = m_InitialBoundingBox;
		m_BoundingBox.Scale(m_vScale);
	}

protected:
	
	// local translation
	mth::Vector3 m_vLocalPos;
	// global translation
	mth::Vector3 m_vGlobalPos;
	// local rotation quaternion
	mth::Quaternion m_qLocalRotation;
	// global rotation quaternion
	mth::Quaternion m_qGlobalRotation;
	// scale
	mth::Vector3 m_vScale;
	// flag to update properties when necessary
	bool m_bUpdateProperties;
	// flag to update lights when necessary
	bool m_bUpdateLights;
	// map of properties
	typedef std::map<NodeProperty::PropertyType,
		NodePropertyPtr> PropertyMap;
	PropertyMap m_Properties;
	// list of lights
	LightList m_lLights;
	// bounding box
	BoundingBox m_BoundingBox;
	// initial bounding box
	BoundingBox m_InitialBoundingBox;

	// pre update
	virtual void PreUpdate();
	// post update 
	virtual void PostUpdate();
	// update property map
	void UpdateProperties();
	// update light list
	void UpdateLights();
};

SmartPointer(TransformNode);

#endif